﻿using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace PInvokeTest
{
    internal class Program
    {
        [DllImport("*")]
        internal static extern void SetIcsNativeaotActiveCode(byte[] activeCode);

        [DllImport("*")]
        public static extern int Native_Add(int a, int b);

        [DllImport("*")]
        internal static extern void SetCSharpDelegate(IntPtr callback);

        public delegate int NativeCallback(int a,int b);

        // 保持引用，避免被 GC 回收

        private static NativeCallback? s_callbackDelegate;

        static byte[] MainThreadAllocBuffer(int size,byte x)
        {
            var buffer = new byte[size];//想办法让buffer回收掉

            for (int i = 0; i < 100; i++)
            {
                buffer[i] = x;
            }
            return buffer;
        }
        static void Main(string[] args)
        {

            var activeCode = new byte[] { 0x3B, 0xD9, 0xDD, 0xF5, 0x00, 0xCE, 0x42, 0x8D, 0x5D, 0xAA, 0xEA, 0x90, 0x81, 0xB8, 0xEE, 0x80, 0xAB, 0xCD, 0x78, 0x71, 0xA3, 0xB1, 0x97, 0x4F, 0x9C, 0x01, 0xCE, 0xE2, 0x58, 0x0A, 0x84, 0xB1, };
            var platform = RuntimeInformation.ProcessArchitecture;
            if (platform == Architecture.Arm)
            {
                SetIcsNativeaotActiveCode(activeCode);
            }

            Console.WriteLine("C# 调用 C 函数 add:");
            int result = Native_Add(3, 5);

            var a = 0xAAAAAAAA;
            var b = 0xBBBBBBBB;
            var mainBuffer=MainThreadAllocBuffer(1024*1024,0x3C);//想办法让buffer回收掉
            var c = 0xCCCCCCCC;
            var d = 0xDDDDDDDD;

            Native_Add((int)a, (int)b);
            Native_Add((int)c, (int)d);
#if true
            var gcAllocThread = new System.Threading.Thread(() =>
            {
                while (true)
                {
                    System.Threading.Thread.Sleep(3000);//等待3s  让主线程停在RhCommonStub再分配内存
                    var buffer2 = new byte[1024 * 1024];

                    for (int i = 0; i < 100; i++)
                    {
                        buffer2[i] = 0x5A;
                    }

                }
            });
            gcAllocThread.IsBackground = true;
            gcAllocThread.Start();
#endif


            var gcThread=new System.Threading.Thread(() =>
            {
                
                while (true)
                {
                    
                    System.Threading.Thread.Sleep(3000);//等待3s  让主线程停在RhCommonStub在执行gc
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();



                }
            });
            gcThread.IsBackground = true;
            gcThread.Start();

            Console.WriteLine("C# 向 C 注册回调，随后让 C 调用该回调：");
            s_callbackDelegate = new NativeCallback(ManagedAdd);
            IntPtr functionPtr = Marshal.GetFunctionPointerForDelegate(s_callbackDelegate);
            SetCSharpDelegate(functionPtr);

            


            Console.WriteLine("演示结束。按任意键退出...");
            Thread.Sleep(-1);
        }
        private static int  ManagedAdd(int a,int b)
        {
            return a + b;
        }


        public enum CanMsgFlag
        {
            CAN_MSG_FLAG_NONE = 0x00,
            CAN_MSG_FLAG_EXTENDED_ID = 0x01,
            CAN_MSG_FLAG_RTR = 0x02,
            CAN_MSG_FLAG_FD = 0x04,
            CAN_MSG_FLAG_BRS = 0x08,
            CAN_MSG_FLAG_ESI = 0x10,
        }

        [StructLayout(LayoutKind.Sequential,Pack =4)]
        public struct CanReceivedStruct
        {
            public int Id;
            public CanMsgFlag Flags;
            public byte Dlc;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] Data;

        }
        [UnmanagedCallersOnly(EntryPoint = "Managed_CanReceived")]
        public static int Managed_CanReceived(IntPtr canReceivedPtr)
        {
            var canReceived = Marshal.PtrToStructure<CanReceivedStruct>(canReceivedPtr);
            Console.WriteLine($"Id: 0x{canReceived.Id:X8}, Flags: {canReceived.Flags}, Dlc: {canReceived.Dlc}, Data: {BitConverter.ToString(canReceived.Data, 0, canReceived.Dlc)}");
            return 0;
        }
    }
}